/**
 * @file       st7735.h
 * @author     mz8023yt
 * @email      mz8023yt@163.com
 * @version    V1.0
 * @date       2022-03-13
 * @brief      st7735 lcd driver
 */

#ifdef __cplusplus
extern "C" {
#endif

#include "st7735.h"
#include <stdint.h>

/**
 * @brief 初始化配置参数列表
 *
 */
struct cmds init_cmds[] = {
	{ 0x11, { 0 }, 0 },
	{ 0x21, { 0 }, 0 },
	{ 0xB1, { 0x05, 0x3A, 0x3A }, 3 },
	{ 0xB2, { 0x05, 0x3A, 0x3A }, 3 },
	{ 0xB3, { 0x05, 0x3A, 0x3A, 0x05, 0x3A, 0x3A }, 6 },
	{ 0xB4, { 0x03 }, 1 },
	{ 0xC0, { 0x62, 0x02, 0x04 }, 3 },
	{ 0xC1, { 0xC0 }, 1 },
	{ 0xC2, { 0x0D, 0X00 }, 2 },
	{ 0xC3, { 0x8D, 0x6A }, 2 },
	{ 0xC4, { 0x8D, 0xEE }, 2 },
	{ 0xC5, { 0x0E }, 1 },
	{ 0xE0, { 0x02, 0x1C, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2D, 0x29, 0x25, 0x2B, 0x39, 0x00, 0x01, 0x03, 0x10 }, 16 },
	{ 0xE1, { 0x03, 0x1D, 0x07, 0x06, 0x2E, 0x2C, 0x29, 0x2D, 0x2E, 0x2E, 0x37, 0x3F, 0x00, 0x00, 0x02, 0x10 }, 16 },
	{ 0x3A, { 0x05 }, 1 },
	{ 0x36, { 0x08 }, 1 },
	{ 0x29, { 0 }, 0 },
	{ 0x00, { 0 }, 0xff },
};

/**
 * @brief 屏幕初始化
 *
 * @param lcd
 */
void st7735_init(struct st7735* lcd)
{
	uint32_t n = 0;

	lcd->ops.pin.rst(LOW);
	lcd->ops.time.msleep(20);
	lcd->ops.pin.rst(HIGH);
	lcd->ops.time.msleep(120);

	while (init_cmds[n].nums != 0xff) {
		lcd->ops.pin.dc(LOW);
		lcd->ops.spi.write(&init_cmds[n].cmd, 1);

		if (!init_cmds[n].nums) {
			n++;
			continue;
		}

		lcd->ops.pin.dc(HIGH);
		lcd->ops.spi.write(init_cmds[n].dats, init_cmds[n].nums);
		n++;
	}

	lcd->ops.pin.bl(HIGH);
}

/**
 * @brief 画点函数
 *
 * @param lcd
 * @param x
 * @param y
 * @param color
 */
void st7735_point_draw(struct st7735* lcd, uint8_t x, uint8_t y, uint16_t color)
{
	uint8_t cmds = 0x00;
	uint8_t dats[4] = { 0x00, 0x00, 0x00, 0x00 };

	/* Column Address Set */
	cmds = 0x2A;
	dats[1] = x + lcd->cfg.fix.xshift;
	dats[3] = x + lcd->cfg.fix.xshift;
	lcd->ops.pin.dc(LOW);
	lcd->ops.spi.write(&cmds, 1);

	lcd->ops.pin.dc(HIGH);
	lcd->ops.spi.write(dats, 4);

	/* Row Address Set */
	cmds = 0x2B;
	dats[1] = y + lcd->cfg.fix.yshift;
	dats[3] = y + lcd->cfg.fix.yshift;
	lcd->ops.pin.dc(LOW);
	lcd->ops.spi.write(&cmds, 1);

	lcd->ops.pin.dc(HIGH);
	lcd->ops.spi.write(dats, 4);

	/* Memory Write */
	cmds = 0x2C;
	lcd->ops.pin.dc(LOW);
	lcd->ops.spi.write(&cmds, 1);

	dats[0] = color >> 8;
	dats[1] = color & 0xff;
	lcd->ops.pin.dc(HIGH);
	lcd->ops.spi.write(dats, 2);
}

/**
 * @brief 矩形填充
 *
 * @param lcd
 * @param x1
 * @param y1
 * @param x2
 * @param y2
 * @param color
 */
void st7735_rect_fill(struct st7735* lcd, uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint16_t* color)
{
	uint8_t cmds = 0x00;
	uint8_t dats[4] = { 0x00, 0x00, 0x00, 0x00 };

	/* Column Address Set */
	cmds = 0x2A;
	lcd->ops.pin.dc(LOW);
	lcd->ops.spi.write(&cmds, 1);

	dats[1] = x1 + lcd->cfg.fix.xshift;
	dats[3] = x2 + lcd->cfg.fix.xshift;
	lcd->ops.pin.dc(HIGH);
	lcd->ops.spi.write(dats, 4);

	/* Row Address Set */
	cmds = 0x2B;
	lcd->ops.pin.dc(LOW);
	lcd->ops.spi.write(&cmds, 1);

	lcd->ops.pin.dc(HIGH);
	dats[1] = y1 + lcd->cfg.fix.yshift;
	dats[3] = y2 + lcd->cfg.fix.yshift;
	lcd->ops.spi.write(dats, 4);

	/* Memory Write */
	cmds = 0x2C;
	lcd->ops.pin.dc(LOW);
	lcd->ops.spi.write(&cmds, 1);

	lcd->ops.pin.dc(HIGH);
	lcd->ops.spi.write((uint8_t*)color, (y2 - y1 + 1) * (x2 - x1 + 1) * 2);
}

void st7735_rect_fill_color(struct st7735* lcd, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
	int i = 0;
	uint8_t cmds = 0x00;
	uint8_t dats[4] = { 0x00, 0x00, 0x00, 0x00 };
	uint32_t cnts = 0;

	/* Column Address Set */
	cmds = 0x2A;
	dats[0] = (x1 + lcd->cfg.fix.xshift) >> 8;
	dats[1] = (x1 + lcd->cfg.fix.xshift) & 0xff;
	dats[2] = (x2 + lcd->cfg.fix.xshift) >> 8;
	dats[3] = (x2 + lcd->cfg.fix.xshift) & 0xff;
	lcd->ops.pin.dc(LOW);
	lcd->ops.spi.write(&cmds, 1);
	lcd->ops.pin.dc(HIGH);
	lcd->ops.spi.write(dats, 4);

	/* Row Address Set */
	cmds = 0x2B;
	dats[0] = (y1 + lcd->cfg.fix.yshift) >> 8;
	dats[1] = (y1 + lcd->cfg.fix.yshift) & 0xff;
	dats[2] = (y2 + lcd->cfg.fix.yshift) >> 8;
	dats[3] = (y2 + lcd->cfg.fix.yshift) & 0xff;
	lcd->ops.pin.dc(LOW);
	lcd->ops.spi.write(&cmds, 1);
	lcd->ops.pin.dc(HIGH);
	lcd->ops.spi.write(dats, 4);

	/* Memory Write */
	cmds = 0x2C;
	cnts = (x2 - x1 + 1) * (y2 - y1 + 1);
	lcd->ops.pin.dc(LOW);
	lcd->ops.spi.write(&cmds, 1);
	lcd->ops.pin.dc(HIGH);
	for (i = 0; i < cnts; i++) {
		dats[0] = color >> 8;
		dats[1] = color & 0xff;
		lcd->ops.spi.write(dats, 2);
	}
}

#ifdef __cplusplus
}
#endif
